package cn.tedu.csmall.passport.service.impl;

import cn.tedu.csmall.passport.ex.ServiceCode;
import cn.tedu.csmall.passport.ex.ServiceException;
import cn.tedu.csmall.passport.mapper.AdminMapper;
import cn.tedu.csmall.passport.mapper.AdminRoleMapper;
import cn.tedu.csmall.passport.mapper.RoleMapper;
import cn.tedu.csmall.passport.pojo.dto.AdminAddNewDTO;
import cn.tedu.csmall.passport.pojo.dto.AdminInformationDTO;
import cn.tedu.csmall.passport.pojo.dto.AdminLoginInfoDTO;
import cn.tedu.csmall.passport.pojo.dto.AdminUpdatePasswordDTO;
import cn.tedu.csmall.passport.pojo.entity.Admin;
import cn.tedu.csmall.passport.pojo.entity.AdminRole;
import cn.tedu.csmall.passport.pojo.vo.AdminInformationVO;
import cn.tedu.csmall.passport.pojo.vo.AdminListItemVO;
import cn.tedu.csmall.passport.pojo.vo.AdminStandardVO;
import cn.tedu.csmall.passport.pojo.vo.AdminUpdatePasswordVO;
import cn.tedu.csmall.passport.security.AdminDetails;
import cn.tedu.csmall.passport.service.IAdminService;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
@Transactional
public class AdminServiceImpl implements IAdminService {
    @Autowired
    private AdminMapper mapper;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AdminRoleMapper adminRoleMapper;
    @Autowired
    private RoleMapper roleMapper;
    @Value("${csmall.jwt.secret-key}")
    private String secretKey;
    @Value("${csmall.jwt.duration-in-minute}")
    private Long durationInMinute;

    public AdminServiceImpl() {
        log.debug("创建业务对象：AdminServiceImpl");
    }

    @Override
    public String login(AdminLoginInfoDTO adminLoginInfoDTO) {
        log.debug("开始处理【登录认证】的业务，参数：{}", adminLoginInfoDTO);

        // 调用AuthenticationManager的authenticate()方法执行认证
        // 在authenticate()方法的执行过程中
        // Spring Security会自动调用UserDetailsService对象的loadUserByUsername()获取用户详情
        // 并根据loadUserByUsername()返回的用户详情自动验证是否启用、判断密码是否正确等
        Authentication authentication
                = new UsernamePasswordAuthenticationToken(
                adminLoginInfoDTO.getUsername(),
                adminLoginInfoDTO.getPassword());
        Authentication authenticateResult
                = authenticationManager.authenticate(authentication);
        log.debug("Spring Security已经完成认证，且认证通过，返回的结果：{}", authenticateResult);
        log.debug("返回认证信息中的当事人（Principal）类型：{}", authenticateResult.getPrincipal().getClass().getName());
        log.debug("返回认证信息中的当事人（Principal）数据：{}", authenticateResult.getPrincipal());

        // 从认证返回结果中取出当事人信息
        AdminDetails principal = (AdminDetails) authenticateResult.getPrincipal();
        Long id = principal.getId();
        log.debug("认证信息中的用户id：{}", id);
        String username = principal.getUsername();
        log.debug("认证信息中的用户名：{}", username);
        Collection<GrantedAuthority> authorities = principal.getAuthorities();
        log.debug("认证信息中的权限：{}", authorities);
        String authorityListString = JSON.toJSONString(authorities);
        log.debug("认证信息中的权限转换为JSON字符串：{}", authorityListString);

        // 生成JWT，并返回
        // 准备Claims值
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", id);
        claims.put("username", username);
        claims.put("authorities", authorityListString);

        // JWT的过期时间
        Date expiration = new Date(System.currentTimeMillis() + durationInMinute * 60 * 1000);
        log.debug("即将生成JWT数据，过期时间：{}", expiration);

        // JWT的组成：Header（头：算法和Token类型）、Payload（载荷）、Signature（签名）
        String jwt = Jwts.builder()
                // Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                // Payload
                .setClaims(claims)
                .setExpiration(expiration)
                // Signature
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();
        log.debug("已经生成JWT数据：{}", jwt);
        return jwt;
    }

    @Override
    public void addNew(AdminAddNewDTO adminAddNewDTO) {
        log.debug("开始处理添加");
        String username = adminAddNewDTO.getUsername();
        if (mapper.countByUsername(username) > 0) {
            String message = "添加管理员失败！名称【" + username + "】已存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
        String email = adminAddNewDTO.getEmail();
        log.debug("检查电子邮件【{}】是否被占用。。。", email);
        if (mapper.countByEmail(email) > 0) {
            String message = "添加管理员失败！邮箱【" + email + "】已存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
        String phone = adminAddNewDTO.getPhone();
        if (mapper.countByPhone(phone) > 0) {
            String message = "添加管理员失败！手机【" + phone + "】已存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
        //创建admin对象，将作为插入时的参数
        //将参数的各属性复制到admin对象中：BeanUtils.copyProperties(..)
        //判断影响行数是否为1
        //不为1则输出添加失败
        Admin admin = new Admin();
        BeanUtils.copyProperties(adminAddNewDTO, admin);
        admin.setLoginCount(0);
        //TODO 加密密码
        String rawPassword = admin.getPassword();
        String encodedPassword = passwordEncoder.encode(rawPassword);
        admin.setPassword(encodedPassword);
        int row = mapper.insert(admin);
        if (row != 1) {
            String message = "添加失败";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
        //检查各角色的ID是否存在
        //获取用户输入角色权限
        Long[] roleIds=adminAddNewDTO.getRoleIds();
        int countByIds=roleMapper.countByIds(roleIds);
        if(countByIds!=roleIds.length){
            // 是：抛出ServiceException（ERR_BAD_REQUEST）
            String message = "添加管理员失败，角色数据错误！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_BAD_REQUEST, message);
        }

        //获取当前时间对象
        LocalDateTime now=LocalDateTime.now();
        //创建新的集合，存储数据
        List<AdminRole> adminRoleList=new ArrayList<>();
        for (int i = 0; i < roleIds.length; i++) {
            //获取新的AdminRole对象，并把数据赋值给对象中，最后添加在集合中
            AdminRole adminRole=new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roleIds[i]);
            adminRole.setGmtCreate(now);
            adminRole.setGmtModified(now);
            adminRoleList.add(adminRole);
        }
        int rows = adminRoleMapper.insertBatch(adminRoleList);
        if(rows!=roleIds.length){
            String message = "添加失败";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
        log.debug("添加管理员成功");
    }

    @Override
    public void deleteById(Long id) {
        AdminStandardVO adminStandardVO = mapper.getAdminVO(id);
        if (adminStandardVO == null) {
            String message = "此id数据不存在";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        int i = mapper.deleteById(id);
        if (i != 1) {
            String message = "删除失败";
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
        int row = adminRoleMapper.deleteByAdmin(id);
        if(row<=0){
            String message = "删除失败";
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
    }

    @Override
    public void setEnable(Long id) {
        AdminStandardVO adminStandardVO = mapper.getAdminVO(id);
        //判断该数据是否存在
        if (adminStandardVO == null) {
            String message = "此id数据不存在";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        //判断该数据是否启用
        if (adminStandardVO.getEnable() == 1) {
            String message = "该品牌已经启用";
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
        //让数据启用
        //创建Admin对象（座位修改数据的方法的参数）
        //向Admin对象中封装id与enable（固定为1）属性的值
        //调用Mapper对象种的up修改品牌数据，并获取返回值
        //判断是否不为1
        //是：抛出异常
        Admin admin = new Admin();
        admin.setId(id);
        admin.setEnable(1);
        int row = mapper.updateById(admin);
        if (row != 1) {
            String message = "启动失败";
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }

    @Override
    public void setDisable(Long id) {
        AdminStandardVO adminStandardVO = mapper.getAdminVO(id);
        if (adminStandardVO == null) {
            String message = "此id数据不存在";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        //判断是否已经禁用
        if (adminStandardVO.getEnable() != 1) {
            //是：此id对应的品牌已经是禁用状态，则抛出异常（ERR_CONFLICT）
            String message = "该品牌已经禁用";
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
        //禁用数据
        //创建Admin对象 封装书信
        Admin admin = new Admin();
        admin.setId(id);
        admin.setEnable(0);
        int row = mapper.updateById(admin);
        if (row != 1) {
            String message = "禁用失败";
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }

    @Override
    public List<AdminListItemVO> list() {
        log.debug("开始处理【查询管理员列表】的业务……");
        return mapper.list();
    }



    @Override
    public void updatePasswordById(Long id, AdminUpdatePasswordDTO adminUpdatePasswordDTO) {
        AdminUpdatePasswordVO adminVO=mapper.getPasswordVO(id);
        if(adminVO==null){
            String message="此管理员用户不存在";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }
        //把adminVO的数据复制到Admin中
        Admin admin=new Admin();
        BeanUtils.copyProperties(adminUpdatePasswordDTO, admin);
        admin.setId(id);
        //加密新的密码
        String rawPassword = admin.getPassword();
        String encodedPassword = passwordEncoder.encode(rawPassword);
        admin.setPassword(encodedPassword);
        //调用mapper进行修改
        int rows = mapper.updatePasswordById(admin);
        if(rows==0){
            String message="修改失败，发生未知错误";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE,message);
        }
        log.debug("修改成功");
    }

    @Override
    public void updateInfoById(Long id,AdminInformationDTO adminInformationDTO) {
        AdminInformationVO adminInformationVO = mapper.getAdminInfoVO(id);
        if(adminInformationVO==null){
            String message="此管理员用户不存在";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }

        Admin admin=new Admin();
        BeanUtils.copyProperties(adminInformationDTO,admin);
        admin.setId(id);

        int rows = mapper.updateInfoById(admin);
        if(rows!=1){
            String message="修改失败，发生未知错误";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE,message);
        }
        log.debug("修改成功");
    }
}
